package crypt;

import static crypt.EncryptUtil.*;

import java.io.Serializable;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * Represent the key and iv to use with the cipher.
 */
@SuppressWarnings("serial")
public class CryptoVariables implements Serializable {

	/* --- Data Members --- */

	/** The encrypted encoded bytes of the secret key */
	private byte[] encryptedKeyEncoded;

	/** The iv to use when deciphering the file's data */
	private byte[] iv;

	/* --- Ctors. --- */

	/**
	 * Construct an instance using parameters
	 * 
	 * @param secretKey
	 *            The SecretKey to use for the encryption/decryption of the
	 *            file's data
	 * @param iv
	 *            The iv to use with when decrypting to the data
	 * @param publicKey
	 *            The RSAPublicKey to use to encrypt the arguement secretKey
	 */
	public CryptoVariables(SecretKey secretKey, byte[] iv, Key publicKey)
			throws InvalidKeyException, NoSuchAlgorithmException,
			NoSuchPaddingException, IllegalBlockSizeException,
			BadPaddingException {

		this.encryptedKeyEncoded = encryptKey(secretKey, publicKey);
		this.iv = iv;
	}

	/* --- Public Methods --- */

	/**
	 * Decrypt the encoded secret key's bytes by RSA using the argument
	 * RSAPrivateKey.<br>
	 * 
	 * @param privateKey
	 *            The RSAPrivateKey to use when decrypting the secret key
	 * @return the decrypted SecretKeySpec which consists of the decrypted bytes
	 *         of the key and the algorithm which is defined is
	 *         {@link EncryptUtil#KEY_ENCRYPTION_ALGORITHM}.
	 */
	public SecretKey decryptKey(Key privateKey)
			throws NoSuchAlgorithmException, NoSuchPaddingException,
			InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
		Cipher keyDecryptor = Cipher.getInstance(KEY_ENCRYPTION_ALGORITHM);

		keyDecryptor.init(Cipher.DECRYPT_MODE, privateKey);
		byte[] decryptedEncodedKey = keyDecryptor.doFinal(encryptedKeyEncoded);
		return new SecretKeySpec(decryptedEncodedKey, KEY_GENERATOR_ALGORITHM);
	}

	/**
	 * @return the IV
	 */
	public byte[] getIV() {
		return iv;
	}

	/* --- Private Methods --- */

	/**
	 * Encrypt the secretKey by RSA using the argument public key
	 * 
	 * @param secretKey
	 *            The SecretKey to encrypt
	 * @param publicKey
	 *            The RSAPublicKey to use for the encryption
	 * @return the encrypted encoded bytes
	 */
	private byte[] encryptKey(SecretKey secretKey, Key publicKey)
			throws NoSuchAlgorithmException, NoSuchPaddingException,
			InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

		Cipher keyEncryptor = Cipher.getInstance(KEY_ENCRYPTION_ALGORITHM);
		keyEncryptor.init(Cipher.ENCRYPT_MODE, publicKey);
		return keyEncryptor.doFinal(secretKey.getEncoded());
	}

}
